Migrate installer to Go#139
Draft
portainer-mike wants to merge 8 commits into
Draft
Conversation
There was a problem hiding this comment.
Pull request overview
This PR migrates the KubeSolo installer from multiple bash scripts to a single compiled Go-based CLI (cmd/installer) with subcommands for install/uninstall/service/download/check/version.
Changes:
- Added a new Go installer CLI (cobra) that performs host detection, preflight checks, binary download/offline install, service setup, and kubeconfig merge.
- Implemented init-system service backends (systemd/OpenRC/SysV/s6/runit/upstart) plus daemon/foreground run modes.
- Added bootstrap script (
scripts/get.sh) and Makefile targets to build/test the installer across supported architectures.
Reviewed changes
Copilot reviewed 27 out of 27 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| scripts/get.sh | Adds a curl/wget bootstrap script that downloads and execs the correct installer binary per arch. |
| cmd/installer/main.go | Introduces the main cobra CLI and wires install/uninstall/service/download/check/version flows. |
| internal/installer/config/config.go | Defines installer configuration defaults and builds kubesolo CLI args. |
| internal/installer/config/config_test.go | Unit tests for Config.CmdArgs(). |
| internal/installer/detect/detect.go | Filesystem-/proc-based detection for arch/libc/init/environment and archive naming. |
| internal/installer/detect/detect_test.go | Unit tests for archive naming, arch mapping, and constants. |
| internal/installer/download/download.go | Downloads/extracts KubeSolo archives and supports offline installation. |
| internal/installer/download/download_test.go | Unit tests for tar.gz extraction, copy, and progress reader. |
| internal/installer/kubeconfig/kubeconfig.go | Waits for admin kubeconfig then merges it into the invoking user’s kubeconfig. |
| internal/installer/preflight/preflight.go | Implements ordered preflight checks (root/hostname/docker/iptables/alpine/cgroups/ports). |
| internal/installer/preflight/preflight_test.go | Tests for hostname regex, controllers, suite, and best-effort env checks. |
| internal/installer/process/process.go | Stops existing KubeSolo processes via /proc scanning and port-owner detection. |
| internal/installer/process/exec.go | Wraps command creation for potential test substitution. |
| internal/installer/process/process_test.go | Unit tests for PID parsing, min duration, ports list, and non-panicking inode parsing. |
| internal/installer/service/manager.go | Defines Manager interface, routing by init system/run mode, and template helpers. |
| internal/installer/service/systemd.go | systemd unit generation/install/uninstall and systemctl invocations. |
| internal/installer/service/openrc.go | OpenRC init script generation/install/uninstall. |
| internal/installer/service/sysvinit.go | SysV init script generation/install/uninstall plus enable/start logic. |
| internal/installer/service/s6.go | s6 service directory/scripts generation and optional supervisor activation. |
| internal/installer/service/runit.go | runit service directory/script generation and enabling via symlink. |
| internal/installer/service/upstart.go | Upstart job generation/install/uninstall via initctl. |
| internal/installer/service/daemon.go | Fallback daemon-mode runner that starts kubesolo detached and writes a PID file. |
| internal/installer/service/daemon_linux.go | Linux-specific SysProcAttr for daemon detachment. |
| internal/installer/service/daemon_other.go | Non-Linux stub to keep builds/tests working on dev machines. |
| internal/installer/service/foreground.go | Foreground run mode that executes kubesolo attached to the current TTY. |
| internal/installer/service/service_test.go | Template rendering tests and init-system routing tests for New(). |
| Makefile | Adds build/test/clean targets for the new installer binary across architectures. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 27 out of 27 changed files in this pull request and generated 8 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Restructure the Go installer into a multi-command CLI tool following the Cilium CLI pattern. Thin cmd/kubesoloctl/main.go entry point delegates to internal/cli package which owns the full cobra command tree. Commands: install, uninstall, upgrade, download, check, kubeconfig, reset, completion, version. Running without a subcommand defaults to install for backward compatibility. - Rename cmd/installer → cmd/kubesoloctl - Rename internal/installer → internal/cli - Split monolithic main.go into per-command files - Add Makefile targets: build-kubesoloctl, test-kubesoloctl - Update scripts/get.sh and CI workflow for new binary name - Bump default version to v1.1.5
Comment on lines
+28
to
+39
| info, err := detect.Detect() | ||
| if err != nil { | ||
| return err | ||
| } | ||
| mgr, err := service.New(info, config.RunModeService) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| if err := mgr.Uninstall(); err != nil { | ||
| return err | ||
| } |
Comment on lines
+120
to
+121
| case detect.InitOpenRC, detect.InitSysV: | ||
| return runCmd("tail", "-f", "/var/log/messages") |
Comment on lines
+11
to
+28
| func checkCmd(cfg *config.Config) *cobra.Command { | ||
| return &cobra.Command{ | ||
| Use: "check", | ||
| Short: "Run pre-flight checks without installing", | ||
| Long: `Validates that this host meets all requirements for KubeSolo. Exits 0 on success.`, | ||
| RunE: func(cmd *cobra.Command, args []string) error { | ||
| info, err := detect.Detect() | ||
| if err != nil { | ||
| return err | ||
| } | ||
| log.Info(). | ||
| Str("arch", info.Arch). | ||
| Str("libc", string(info.LibC)). | ||
| Str("init", string(info.InitSystem)). | ||
| Str("env", string(info.Environment)). | ||
| Msg("host detected") | ||
| return preflight.RunSuite(preflight.Suite(cfg.InstallPrereqs, cfg.PprofServer)) | ||
| }, |
Comment on lines
+72
to
+76
| log.Info().Msg("starting KubeSolo service (fresh cluster)...") | ||
| if _, err := service.New(info, config.RunModeService); err != nil { | ||
| log.Info().Msg("reset complete — start KubeSolo manually to initialize a fresh cluster") | ||
| return nil | ||
| } |
Comment on lines
+223
to
+247
| # Supported targets: linux/amd64, linux/arm64, linux/arm (armhf), linux/riscv64 | ||
|
|
||
| KUBESOLOCTL_LDFLAGS = -s -w \ | ||
| -X main.Version=$(VERSION) \ | ||
| -X main.Commit=$(COMMIT) \ | ||
| -X main.BuildDate=$(BUILD_DATE) | ||
|
|
||
| KUBESOLOCTL_OUTPUT ?= ./dist/kubesoloctl-$(GOOS)-$(GOARCH) | ||
|
|
||
| # Build kubesoloctl for the current GOOS/GOARCH. | ||
| # Pass GOARM=7 when targeting arm (armhf/ARMv7), e.g.: make build-kubesoloctl GOARCH=arm GOARM=7 | ||
| .PHONY: build-kubesoloctl | ||
| build-kubesoloctl: | ||
| @mkdir -p $(dir $(KUBESOLOCTL_OUTPUT)) | ||
| CGO_ENABLED=0 GOOS=$(GOOS) GOARCH=$(GOARCH) GOARM=$(GOARM) go build \ | ||
| -ldflags="$(KUBESOLOCTL_LDFLAGS)" \ | ||
| -o $(KUBESOLOCTL_OUTPUT) \ | ||
| ./cmd/kubesoloctl | ||
|
|
||
| # Build kubesoloctl for all supported architectures | ||
| .PHONY: build-kubesoloctl-all | ||
| build-kubesoloctl-all: | ||
| GOARCH=amd64 KUBESOLOCTL_OUTPUT=./dist/kubesoloctl-linux-amd64 make build-kubesoloctl | ||
| GOARCH=arm64 KUBESOLOCTL_OUTPUT=./dist/kubesoloctl-linux-arm64 make build-kubesoloctl | ||
|
|
Comment on lines
+33
to
+42
| name: build kubesoloctl-linux-${{ matrix.goarch }} | ||
| runs-on: ubuntu-latest | ||
| needs: [test] | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| include: | ||
| - goarch: amd64 | ||
| - goarch: arm64 | ||
| steps: |
Comment on lines
+31
to
+40
| # detect architecture | ||
| ARCH=$(uname -m) | ||
| case "$ARCH" in | ||
| x86_64) ARCH=amd64 ;; | ||
| aarch64) ARCH=arm64 ;; | ||
| *) | ||
| printf 'error: unsupported architecture: %s\n' "$ARCH" >&2 | ||
| printf 'supported: x86_64 (amd64), aarch64 (arm64)\n' >&2 | ||
| exit 1 | ||
| ;; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
KS-45: Go installer — replaces install.sh, kubesolo-service.sh, uninstall.sh
Rewrites the three bash installer scripts as a single compiled Go CLI binary (
cmd/installer). Built withCGO_ENABLED=0so one binary per architecture covers both glibc and musl systems, eliminating the libc split the bash scripts handle at runtime.Supported targets
linux/amd64,linux/arm64,linux/arm(armhf),linux/riscv64CLI
All flags have
KUBESOLO_*environment variable equivalents.What's new
cmd/installer/— cobra CLI entry point. Six subcommands: install (default), uninstall, service, download, check, version.uninstallremoves the service, binary, and optionally the data directory (--purge).internal/installer/config/—Configstruct and constants.CmdArgs()builds the argument list passed to the kubesolo binary using bare boolean flags (--debugnot--debug=true) to match kubesolo's flag parser.internal/installer/detect/— host detection with no subprocess calls. Detects arch, libc (musl vs glibc via/lib/ld-musl-*.so.1), init system (from filesystem landmarks — nowhich/command -v), and environment (container, SBC).internal/installer/preflight/— seven ordered checks: root, hostname RFC 1123, Docker conflict, iptables xt_comment module, nftables+iptables (Alpine only, installs viaapk addif--install-prereqs), cgroups (enables Alpine OpenRC cgroups service proactively if needed), required ports. Stop runs before preflight so ports held by an existing KubeSolo installation don't cause false failures.internal/installer/process/— stops running KubeSolo before reinstalling. Reads/proc/*/exesymlinks, SIGTERMs with exponential backoff, SIGKILLs stragglers. Port holders found via/proc/net/tcp[6]inode mapping. No dependency onlsof,ss, ornetstat.internal/installer/download/— online and offline install. Extracts by base name so nested tar paths (kubesolo-v1.1.2-linux-amd64/kubesolo) are handled correctly. Atomic install viaos.Rename; cross-device fallback (tmpfs → ext4 on Alpine) explicitlychmod 0755es the staged binary before the final rename.internal/installer/service/— seven init system backends behind a commonManagerinterface: systemd, OpenRC, SysV, s6, runit, upstart, daemon (fallback). All templates support optional proxy environment injection.daemon_linux.go/daemon_other.gosplit via build tags keeps the package compilable on macOS for local development.internal/installer/kubeconfig/— waits up to 30s for the admin kubeconfig to appear, then merges it into the real user's~/.kube/configviakubectl config view --flatten. Real user resolved in order:SUDO_USER(sudo),DOAS_USER(doas),/proc/self/loginuid(kernel login UID, preserved across any privilege escalation — reliable catch-all fordoason Alpine), fallback to current user. Source kubeconfig ischowned to the real user soKUBECONFIG=<path>in shell profiles keeps working.scripts/get.sh— bootstrap script forget.kubesolo.io. Detects arch viauname -m, downloads the correctinstaller-linux-<arch>binary, and execs it. SupportsKUBESOLO_VERSION,KUBESOLO_INSTALLER_BASE_URL, andKUBESOLO_FLAT_URLSfor version pinning and internal mirrors.Makefile— addsbuild-installer,build-installer-all,test-installer,clean-installertargets.Building